哈夫曼编码与解码(贪心算法) C++实现

哈夫曼编码与解码(贪心算法) C++实现

原理

将原有的定长编码改为变长编码,字母次数出现多的使用小位数编码,字母次数出现少的使用多位数编码,总编码长度为:
B ( T ) = ∑ c ∈ C c . f r e q × d T ( c ) B(T)=\sum_{c\in C}c.freq\times d_{T}(c) B(T)=cCc.freq×dT(c)
个二进制位。

其中 c . f r e q c.freq c.freq表示 c c c在文本中出现的频率,$ d_{T}© 表 示 字 符 表示字符 c 的 码 字 的 长 度 , 也 可 表 示 为 的码字的长度,也可表示为 c$的叶结点在树中的深度。

哈夫曼编码通常可以节省 20 % ∼ 90 % 20\%\sim90\% 20%90%的空间。

源代码

Huffman_Code.h

#ifndef _HUFFMAN_CODE_H_
#define _HUFFMAN_CODE_H_

#include <map>
#include <string>
#include <memory>
#include <vector>
#include <fstream>
#include <utility>
#include <iostream>
#include <algorithm>
#include <stdexcept>

using std::make_shared;
using std::shared_ptr;
using std::string;
using std::vector;
using std::pair;
using std::map;
using std::cout;
using std::endl;

class H_BST {
	struct Node {
		pair<string, size_t> data;
		shared_ptr<Node> left = nullptr;
		shared_ptr<Node> right = nullptr;
		shared_ptr<Node> parent = nullptr;
	};

	shared_ptr<Node> Root = nullptr;
	//Binary_Search_Tree with Huffman-Code.
	vector<shared_ptr<Node>> Vec_Node;
	//Letters and bijection codes.
	map<string, string> Map_Code;
	//All of Letters's code.
	string Binary_Code;

public:
	H_BST() = default;
	~H_BST() = default;

	//Reading the data.
	void Huffman_Code(string const &temp_str) {
		string temp_i;
		map<string, size_t> temp_Map;

		for(auto &i : temp_str) {
			temp_i = i;
			++temp_Map[temp_i];
		}

		Huffman_Encoder(temp_Map);

		for (auto &i : temp_str) {
			temp_i = i;
			Binary_Code += Map_Code[temp_i];
		}

		Huffman_Decoder(Vec_Node);
	}

	//Reading the data from file.
	void Huffman_Code_File(string const &filename) {
		string temp_i, temp_str;
		std::ifstream file(filename);
		map<string, size_t> temp_Map;

		try {
			if (file) {
				while (!file.eof()) {
					string temp_s;
					getline(file, temp_s);
					temp_str += temp_s;
				}
			}
			else {
				throw std::runtime_error("Not find the file.");
			}
		}
		catch (std::runtime_error e) {
			cout << e.what() << endl;
		}

		for (auto &i : temp_str) {
			temp_i = i;
			++temp_Map[temp_i];
		}

		Huffman_Encoder(temp_Map);

		for (auto &i : temp_str) {
			temp_i = i;
			Binary_Code += Map_Code[temp_i];
		}

		Huffman_Decoder_File(Vec_Node);
	}

	//Encodering and saving the result.
	void Huffman_Encoder(map<string, size_t> &temp_Map) {
		auto temp_n = temp_Map.size();
		vector<shared_ptr<Node>> temp_VecNode;

		for(auto &i : temp_Map) {
			auto temp_ptr = make_shared<Node>();
			temp_ptr->data.first = i.first;
			temp_ptr->data.second = i.second;

			temp_VecNode.push_back(temp_ptr);
		}

		for(auto i = 1; i != temp_n; ++i) {
			std::sort(temp_VecNode.begin(), temp_VecNode.end(), [](shared_ptr<Node> N1, shared_ptr<Node> N2) {return N1->data.second < N2->data.second; });
			auto new_Node = make_shared<Node>();

			new_Node->left = temp_VecNode[0];
			new_Node->right = temp_VecNode[1];
			new_Node->data.second = temp_VecNode[0]->data.second + temp_VecNode[1]->data.second;

			temp_VecNode.erase(temp_VecNode.begin(), temp_VecNode.begin() + 2);
			temp_VecNode.push_back(new_Node);
		}

		Vec_Node = temp_VecNode;

		Save_Coder(Vec_Node[0], "");
	}

	//Saving the unique code of letters.
	void Save_Coder(shared_ptr<Node> Root, string const &code) {
		if (Root) {
			if (!Root->left && !Root->right) {
				Map_Code.insert(std::make_pair(Root->data.first, code));
				std::cout << Root->data.first << " -> " << code << std::endl;
			}
			else {
				Save_Coder(Root->left, code + "0");
				Save_Coder(Root->right, code + "1");
			}
		}
	}

	//Decodering and outputting the result.
	void Huffman_Decoder(vector<shared_ptr<Node>> const &Vec_Node) {
		auto Ptr = Vec_Node[0];
		string temp_i;

		for(auto &i : Binary_Code) {
			temp_i = i;
			if(temp_i == "0") {
				Ptr = Ptr->left;
				if(Ptr->left == nullptr && Ptr->right == nullptr) {
					cout << Ptr->data.first;
					Ptr = Vec_Node[0];
				}
			}
			if(temp_i == "1") {
				Ptr = Ptr->right;
				if (Ptr->left == nullptr && Ptr->right == nullptr) {
					cout << Ptr->data.first;
					Ptr = Vec_Node[0];
				}
			}
		}

		cout << endl;
	}

	//Decodering and outputting the result in the file.
	void Huffman_Decoder_File(vector<shared_ptr<Node>> const &Vec_Node) {
		auto Ptr = Vec_Node[0];
		std::ofstream out("file_encoder_to_decoder.txt");
		string temp_i;

		for (auto &i : Binary_Code) {
			temp_i = i;
			if (temp_i == "0") {
				Ptr = Ptr->left;
				if (Ptr->left == nullptr && Ptr->right == nullptr) {
					out << Ptr->data.first;
					Ptr = Vec_Node[0];
				}
			}
			if (temp_i == "1") {
				Ptr = Ptr->right;
				if (Ptr->left == nullptr && Ptr->right == nullptr) {
					out << Ptr->data.first;
					Ptr = Vec_Node[0];
				}
			}
		}
	}
};

#endif // !_HUFFMAN_CODE_H_

测试代码:

#include "Huffman_Code.h"

using namespace std;

int main() {
	H_BST A;
	A.Huffman_Code("aaaaaaaaaaaaaaaaaaaaaaaaassssssssssssssddddddddddddddddddeeeeeeeeeeeeefgssssssssssssssqqqqqq -???>>> <<<!@$%&(%^$#@#@");
	//A.Huffman_Code_File("file_name.data");//读取文件。

	return 0;
}
  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++哈夫曼编码贪心算法实现: ```c++ #include <iostream> #include <queue> #include <vector> using namespace std; // 哈夫曼树节点 struct Node { char ch; int freq; Node* left; Node* right; Node(char c, int f) : ch(c), freq(f), left(nullptr), right(nullptr) {} }; // 小根堆比较函数 struct compare { bool operator()(Node* l, Node* r) { return l->freq > r->freq; } }; // 生成哈夫曼树 Node* huffmanTree(const string& str) { // 统计字符频率 vector<int> freq(256, 0); for (auto& c : str) { freq[c]++; } // 构建小根堆 priority_queue<Node*, vector<Node*>, compare> pq; for (int i = 0; i < 256; i++) { if (freq[i] > 0) { pq.push(new Node(i, freq[i])); } } // 不断合并小根堆中的节点,直到只剩一个节点 while (pq.size() > 1) { Node* left = pq.top(); pq.pop(); Node* right = pq.top(); pq.pop(); Node* parent = new Node('#', left->freq + right->freq); parent->left = left; parent->right = right; pq.push(parent); } return pq.top(); } // 生成哈夫曼编码 void huffmanCode(Node* root, string code, vector<string>& result) { if (!root) { return; } if (root->ch != '#') { result[root->ch] = code; } huffmanCode(root->left, code + "0", result); huffmanCode(root->right, code + "1", result); } int main() { string str = "hello world"; Node* root = huffmanTree(str); vector<string> result(256); huffmanCode(root, "", result); // 输出生成的哈夫曼编码 for (int i = 0; i < 256; i++) { if (!result[i].empty()) { cout << (char)i << ": " << result[i] << endl; } } return 0; } ``` 在这个实现中,我们首先统计字符串中每个字符出现的频率,并将它们存储在一个大小为256的数组中。然后,我们构建一个小根堆,其中每个节点都代表一个字符及其对应的频率,我们将小根堆中频率最小的两个节点合并为一个新节点,并将它们的和作为新节点的频率。这个过程一直持续到小根堆中只剩下一个节点为止,这个节点就是哈夫曼树的根节点。 接下来,我们沿着哈夫曼树,为每个字符生成一个哈夫曼编码。当我们遍历到一个叶子节点时,我们就将其对应的字符和编码存储在一个vector中。 最后,我们可以输出每个字符的哈夫曼编码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值